package ru.xpparty.scanner;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import ru.xpparty.scanner.model.ScanRequest;

/**
 * Heart of program. Performs call of underlying classes by given request and
 * returns result of scanning.
 * 
 * @author xp.party
 * 
 */
public class Scanner {
	private SocketScannerFactory factory;

	/**
	 * 
	 * @param factory
	 *            factory of socket scanners
	 */
	public void setSocketScannerFactory(SocketScannerFactory factory) {
		this.factory = factory;
	}
	
	private ExecutorService service;
	
	public ExecutorService getService() {
		return service;
	}

	public void setService(ExecutorService service) {
		this.service = service;
	}

	/**
	 * Performs scanning ports on host found in given request. Returns result of
	 * scanning.
	 * 
	 * @param request
	 *            request to scanner
	 * @return result of scanning
	 */
	public ScanResult scan(ScanRequest request) {
		ScanResult scanResult = new ScanResult(request.getHost());
		
		List<ScannerCallable> callables = new ArrayList<Scanner.ScannerCallable>();
		for (int port = request.getStartPort(), end = request.getEndPort(); port <= end; port++) {
			callables.add(new ScannerCallable(request.getHost(), port));
		}
		
		try {
			int port = request.getStartPort();
			List<Future<PortStatus>> result = service.invokeAll(callables);
			for (Future<PortStatus> future : result) {
				scanResult.append(port++, future.get());				
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return scanResult;
	}	
	private class ScannerCallable implements Callable<PortStatus> {

		private final String host;
		private final int port;
		
		public ScannerCallable(String host, int port) {
			this.host = host;
			this.port = port;
		}
		
		@Override
		public PortStatus call() throws Exception {
			SocketScanner socketScanner = factory.create(host, port);
			return socketScanner.scan();
		}		
	}

}
